﻿// -----------------------------------------------------------------------
// <copyright file="Serializator.cs" company="DarkBone">
// Serialization class
// </copyright>
// -----------------------------------------------------------------------

namespace DarkBone
{
   using System;
   using System.Diagnostics;
   using System.IO;
   using System.IO.Compression;
   using System.Runtime.Serialization.Formatters.Binary;

   /// <summary>
   /// Serializator class
   /// </summary>
   public sealed class Serializator
   {
            /// <summary>
      /// Serializes and compress serializable object
      /// </summary>
      /// <param name="obj">
      /// The object to be serialized
      /// </param>
      /// <returns>
      /// Serialized data
      /// </returns>
      public static SerializedObject SerializeObj(object obj)
      {
         byte[] bytes;
         using (var memStream = new MemoryStream())
         {
            var formatter = new BinaryFormatter();
            formatter.Serialize(memStream, obj);
            bytes = memStream.ToArray();
            memStream.Close();
         }

         using (var memStream = new MemoryStream())
         {
            using (var zipStream = new GZipStream(memStream, CompressionMode.Compress, true))
            {
               zipStream.Write(bytes, 0, bytes.Length);
               zipStream.Close();
               memStream.Seek(0, SeekOrigin.Begin);
               return new SerializedObject(memStream.ToArray(), obj.GetType());
            }
         }
      }

      /// <summary>
      /// Deserializes container into object
      /// </summary>
      /// <typeparam name="T">
      /// Object type
      /// </typeparam>
      /// <param name="container">
      /// The buffer to be deserialized.
      /// </param>
      /// <returns>
      /// Deserialized Object
      /// </returns>
      public static T DeserializeObj<T>(byte[] container)
      {
         using (var memStream = new MemoryStream())
         {
            using (var containerStream = new MemoryStream(container))
            {
               using (var zipStream = new GZipStream(containerStream, CompressionMode.Decompress))
               {
                  zipStream.CopyTo(memStream);
                  zipStream.Close();
                  memStream.Seek(0, SeekOrigin.Begin);
                  var formatter = new BinaryFormatter();
                  return (T)formatter.Deserialize(memStream);
               }
            }
         }
      }
      
      /// <summary>
      /// Serialized Object
      /// </summary>
      public struct SerializedObject
      {
         /// <summary>
         /// buffer containing serialized object
         /// </summary>
         public readonly byte[] Buffer;
         
         /// <summary>
         /// Object Type
         /// </summary>
         public readonly Type ObjType;

         /// <summary>
         /// Initializes a new instance of the <see cref="SerializedObject"/> struct.
         /// </summary>
         /// <param name="buffer">
         /// The buffer.
         /// </param>
         /// <param name="objType">
         /// The object Type.
         /// </param>
         public SerializedObject(byte[] buffer, Type objType)
            : this()
         {
            this.Buffer = buffer;
            Debug.WriteLine("serialized object: " + buffer.Length);
            this.ObjType = objType;
         }
      }
   }
}
